﻿namespace Dyao.Book.Contract
{
    /// <summary>
    /// 任务中心参数
    /// </summary>
    public class DefaultTaskCenterParameters : TaskCenterParametersBase
    {
        /// <summary>序列化的字符串</summary>
        internal protected string _parametersString;

        /// <summary>序列化的字符串获取工厂</summary>
        internal protected Func<string> _paramtersStringFactory;

        /// <summary>反序列化工厂</summary>
        internal protected Func<Type, object, object> _deserialize;

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="p"></param>
        public DefaultTaskCenterParameters(ITaskCenterParameters p)
            : this(p.ToString()
                  , (p is TaskCenterParametersBase b)
                      ? (b.Parameters)
                      : p.GetKeys().ToDictionary(k => k, (k) => { p.TryGetValue(k, out object v); return v; })
                  , p.Deserialize)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="p"></param>
        public DefaultTaskCenterParameters(DefaultTaskCenterParameters p) : base(p._getParametersDictFactory)
        {
            this._parametersString = p._parametersString;
            this._paramtersStringFactory = p._paramtersStringFactory;
            this._parametersDict = p._parametersDict;
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="parametersString">参数字符串</param>
        /// <param name="parameters">参数</param>
        /// <param name="deserialize">反序列化器</param>
        public DefaultTaskCenterParameters(string parametersString, IDictionary<string, object> parameters, Func<Type, object, object> deserialize) : base(parameters)
        {
            this._parametersString = parametersString;
            this._deserialize = deserialize;
        }

        /// <summary>
        /// 任务中心构造
        /// </summary>
        /// <param name="paramtersStringFactory"></param>
        /// <param name="parameters"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(Func<string> paramtersStringFactory, IDictionary<string, object> parameters, Func<Type, object, object> deserialize) : base(parameters)
        {
            this._paramtersStringFactory = paramtersStringFactory;
            this._deserialize = deserialize;
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="parametersString"></param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(string parametersString, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize)
            : base(dictFactory)
        {
            this._parametersString = parametersString;
            this._deserialize = deserialize;
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="paramtersStringFactory"></param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(Func<string> paramtersStringFactory, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize) : base(dictFactory)
        {
            this._paramtersStringFactory = paramtersStringFactory;
            this._deserialize = deserialize;
        }

        /// <summary>
        /// 获取参数原始字符串
        /// </summary>
        /// <returns>参数原始字符串</returns>
        protected override string GetParametersString() => _parametersString ??= _paramtersStringFactory?.Invoke();

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object Deserialize(Type type, object value) => _deserialize(type, value);

        /// <summary>
        /// 根据 <typeparamref name="T"/> 创建 泛型实例 <see cref="ITaskCenterParameters"/>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parametersString"></param>
        /// <param name="parametersStringFacotry"></param>
        /// <param name="parameters"></param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize"></param>
        /// <returns></returns>
        public static ITaskCenterParameters<T> Create<T>(string parametersString, Func<string> parametersStringFacotry, IDictionary<string, object> parameters, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize)
            where T : class
        {
            return (ITaskCenterParameters<T>)Create(typeof(T), parametersString, parametersStringFacotry, parameters, dictFactory, deserialize);
        }

        /// <summary>
        /// 根据 <paramref name="modelType"/> 创建 泛型实例 <see cref="ITaskCenterParameters"/>
        /// </summary>
        /// <param name="modelType">model类型</param>
        /// <param name="parametersString">参数字符串</param>
        /// <param name="parametersStringFacotry"></param>
        /// <param name="parameters">参数字典</param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize">反序列化方法</param>
        /// <returns></returns>
        public static ITaskCenterParameters Create(Type modelType, string parametersString, Func<string> parametersStringFacotry, IDictionary<string, object> parameters, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize)
        {
            if (!modelType.IsClass) throw new ArgumentException($"{nameof(modelType)} 类型必须是class。");
            if (parametersString == null && parametersStringFacotry == null) throw new ArgumentException($"{nameof(parametersString)}、{nameof(parametersStringFacotry)}二者必须有一个不为null");
            if (parameters == null && dictFactory == null) throw new ArgumentException($"{nameof(parameters)}、{nameof(dictFactory)}二者必须有一个不为null");
            if (deserialize is null) throw new ArgumentNullException(nameof(deserialize));

            var type = typeof(DefaultTaskCenterParameters<>).MakeGenericType(modelType);

            var types = new List<Type>(3);
            var values = new List<object>(3);

            if (parametersString != null)
            {
                values.Add(parametersString);
                types.Add(typeof(string));
            }
            else
            {
                values.Add(parametersStringFacotry);
                types.Add(typeof(Func<string>));
            }

            if (parameters != null)
            {
                values.Add(parameters);
                types.Add(typeof(IDictionary<string, object>));
            }
            else
            {
                values.Add(dictFactory);
                types.Add(typeof(Func<IDictionary<string, object>>));
            }

            values.Add(deserialize);
            types.Add(typeof(Func<Type, object, object>));

            var constructor = type.GetConstructor(types.ToArray());

            var instance = (ITaskCenterParameters)constructor.Invoke(values.ToArray());

            return instance;
        }

    }

    /// <summary>
    /// 任务中心参数
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DefaultTaskCenterParameters<T> : DefaultTaskCenterParameters, ITaskCenterParameters<T>, ITaskCenterParameters
        where T : class
    {
        private T _model;
        private bool _isLoadModel;

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="p"></param>
        public DefaultTaskCenterParameters(ITaskCenterParameters p) : base(p)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="parameters"></param>
        public DefaultTaskCenterParameters(DefaultTaskCenterParameters parameters) : base(parameters)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="parametersString"></param>
        /// <param name="parameters"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(string parametersString, IDictionary<string, object> parameters, Func<Type, object, object> deserialize)
            : base(parametersString, parameters, deserialize)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="paramtersStringFactory"></param>
        /// <param name="parameters"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(Func<string> paramtersStringFactory, IDictionary<string, object> parameters, Func<Type, object, object> deserialize)
           : base(paramtersStringFactory, parameters, deserialize)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="parametersString"></param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(string parametersString, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize)
            : base(parametersString, dictFactory, deserialize)
        {
        }

        /// <summary>
        /// 任务中心参数字典构造
        /// </summary>
        /// <param name="paramtersStringFactory"></param>
        /// <param name="dictFactory"></param>
        /// <param name="deserialize"></param>
        public DefaultTaskCenterParameters(Func<string> paramtersStringFactory, Func<IDictionary<string, object>> dictFactory, Func<Type, object, object> deserialize)
            : base(paramtersStringFactory, dictFactory, deserialize)
        {
        }

        /// <summary>
        /// model
        /// </summary>
        public virtual T Model
        {
            get
            {
                if (!_isLoadModel)
                {
                    TryDeserializeParametersTo(out _model);
                    _isLoadModel = true;
                }

                return _model;
            }
        }
    }
}
